package ac.svn.accesscontrol.controller;

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JFileChooser;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import ac.notification.event.INotificationListener;
import ac.notification.event.NotificationEvent;
import ac.notification.manager.NotificationRegistrar;
import ac.svn.accesscontrol.store.IResources;
import ac.svn.accesscontrol.store.ISVNIdentifier;
import ac.svn.accesscontrol.store.ISVNItem;
import ac.svn.accesscontrol.store.SVNUser;
import ac.svn.accesscontrol.ui.IUIConstants;
import ac.svn.accesscontrol.ui.JMenu;
import ac.svn.accesscontrol.ui.UIComponentLibrary;
import ac.svn.accesscontrol.ui.window.PasswordUtilityDailog;
import ac.svn.accesscontrol.utils.Utility;

public class UserPasswordCreationController implements
INotificationListener,ISVNIdentifier{


	private JFileChooser fileChooserDialog;
	private PasswordUtilityDailog passwordUtilityDailog;
	private JMenuItem createPasswordMI;

	public UserPasswordCreationController()
	{
		initComponents();
		intergrate();
		registerListeners();
		NotificationRegistrar.registerListener(this);
	}



	private void intergrate()
	{
		JMenu toolMenu = (JMenu) UIComponentLibrary.getComponent(IUIConstants.M_TOOL_MENU);
		if(null != toolMenu)
		{
			createPasswordMI = new JMenuItem("Password Utility");
			createPasswordMI.setIcon(Utility.getImageIcon(IResources.LOC_ICN_PWD_SMALL));

			createPasswordMI.addActionListener(new ActionListener() 
			{
				@Override
				public void actionPerformed(ActionEvent e) 
				{
					NotificationEvent event = new NotificationEvent(CMD_SHOW_PASSWORD_UTIL);
					NotificationRegistrar.dispatchNotification(event);	
				}
			});

			toolMenu.addSeparator();
			toolMenu.add(createPasswordMI);
		}	
	}

	private void initComponents()
	{
		fileChooserDialog = new JFileChooser();
		fileChooserDialog.setFileSelectionMode(JFileChooser.FILES_ONLY);
		fileChooserDialog.setMultiSelectionEnabled(false);
		passwordUtilityDailog = new PasswordUtilityDailog();
		passwordUtilityDailog.setIconImage(Utility.getImage(IResources.LOC_ICN_PWD_SMALL));
	}



	private void registerListeners() 
	{
		passwordUtilityDailog.getBrowserAuthFileBtn().addActionListener(new FileBrowseTask(passwordUtilityDailog.getPwdFilePathTxt()));
		passwordUtilityDailog.getBrowserUtilityFileBtn().addActionListener(new FileBrowseTask(passwordUtilityDailog.getUtilityPathTxt()));

		passwordUtilityDailog.getCreateUserBtn().addActionListener(new ActionListener()
		{
			@Override
			public void actionPerformed(ActionEvent e) 
			{
				passwordUtilityDailog.getTextPaneProgress().setText("");
				addTextToProgress("Creating User..");
				addTextToProgress("Validating Data provided..");
				if(validateData())
				{
					addTextToProgress("Validation succeeded!");
					EventQueue.invokeLater(new Runnable() {
						@Override
						public void run() {
							addTextToProgress("Executing password utils.."); 
							executeProcess();
						}
					});
				}
				else
				{
					addTextToProgress("Process Aborted due to validation errors!");
				}
			}
		});

		CmdLineDisplay cmdLineDisplay = new CmdLineDisplay();

		passwordUtilityDailog.getUserNameTxt().addKeyListener(cmdLineDisplay);
		passwordUtilityDailog.getUserNameTxt().addFocusListener(cmdLineDisplay);

		passwordUtilityDailog.getUtilityPathTxt().addKeyListener(cmdLineDisplay);
		passwordUtilityDailog.getUtilityPathTxt().addFocusListener(cmdLineDisplay);

		passwordUtilityDailog.getPasswordTxt().addKeyListener(cmdLineDisplay);
		passwordUtilityDailog.getPasswordTxt().addFocusListener(cmdLineDisplay);

		passwordUtilityDailog.getPwdFilePathTxt().addKeyListener(cmdLineDisplay);
		passwordUtilityDailog.getPwdFilePathTxt().addFocusListener(cmdLineDisplay);
	}



	protected void executeProcess() 
	{
		String cmdString = getCommandLineText();

		try 
		{
			Process process = Runtime.getRuntime().exec(cmdString);
			BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
			String line = "";
			while(null != (line = br.readLine()))
			{
				addTextToProgress(line);
			}
			br.close();
			int exitStatus = process.exitValue();
			if(0 == exitStatus)
			{
				addTextToProgress("Password Creation successful!");
				resetUI();
			}
			else
			{
				addTextToProgress(String.format("Process returned %d exit status, change might not be complete, Review manually!",exitStatus));
			}
		}
		catch (IOException e) 
		{
			e.printStackTrace();
			addTextToProgress("Error Occurred..");
			addTextToProgress(e.getMessage());
		}
	}



	private void addTextToProgress(String message) 
	{
		String currentText = passwordUtilityDailog.getTextPaneProgress().getText();
		passwordUtilityDailog.getTextPaneProgress().setText(String.format("%s\n%s", currentText,message));
		passwordUtilityDailog.getTextPaneProgress().setCaretPosition(passwordUtilityDailog.getTextPaneProgress().getText().length());
	}



	protected boolean validateData() 
	{
		boolean dataValid = true;
		String errorMessage = "<HTML>Error Summary";


		String txt = passwordUtilityDailog.getUserNameTxt().getText();
		dataValid  &= validateString(txt, false, false, null);

		if(false == dataValid)
		{
			errorMessage += "<br>- User Name is a required field";
		}

		txt = passwordUtilityDailog.getPasswordTxt().getText();
		dataValid  &= validateString(txt, false, false, null);

		if(false == dataValid)
		{
			errorMessage += "<br>- Password is a required field";
		}

		txt = passwordUtilityDailog.getPwdFilePathTxt().getText();
		dataValid  &= validateString(txt, false, false, null);

		if(false == dataValid)
		{
			errorMessage += "<br>- File name is a required field";
		}

		txt = passwordUtilityDailog.getUtilityPathTxt().getText();
		dataValid  &= validateString(txt, false, false, "htpasswd.exe");

		if(false == dataValid)
		{
			errorMessage += "<br>- Path does not point to a valid password utility!";
		}

		if(false == dataValid)
		{
			JOptionPane.showMessageDialog(passwordUtilityDailog, errorMessage, "Error Occurred!", JOptionPane.ERROR_MESSAGE);
		}

		return dataValid;
	}



	@Override
	public Set<String> declaredSubscriptionSet() {
		Set<String> subscriptions = new HashSet<String>();
		subscriptions.add(CMD_SHOW_PASSWORD_UTIL);
		subscriptions.add(CMD_CHANGE_PASSWORD);
		return subscriptions;
	}

	@Override
	public void receiveEvent(NotificationEvent notificationEvent) {
		final String neId = notificationEvent.getPropertyIdentifier();
		if(neId.contains(CMD_SHOW_PASSWORD_UTIL))
		{
			handleUtilShowCommand(notificationEvent);
		}
		else if(neId.contains(CMD_CHANGE_PASSWORD))
		{
			handlePasswordChangeCommand(notificationEvent);
		} 
	}

	private void handlePasswordChangeCommand(NotificationEvent notificationEvent) 
	{
		ISVNItem svnUser = (ISVNItem) notificationEvent.getPropertyValue();
		if((null != svnUser) && (svnUser instanceof SVNUser))
		{
			passwordUtilityDailog.getUserNameTxt().setText(svnUser.getId());			
		}

		passwordUtilityDailog.setVisible(true);
	}



	private void handleUtilShowCommand(NotificationEvent notificationEvent) 
	{
		passwordUtilityDailog.setVisible(true);	
	}

	public class FileBrowseTask implements ActionListener
	{
		private JTextField targetTextField;

		public FileBrowseTask(JTextField targetTxt)
		{
			this.targetTextField = targetTxt;
		}


		@Override
		public void actionPerformed(ActionEvent e) 
		{
			browseFile();
		}

		private void browseFile() 
		{
			int selOption = fileChooserDialog.showOpenDialog(passwordUtilityDailog);
			if(JFileChooser.APPROVE_OPTION == selOption)
			{
				File file = fileChooserDialog.getSelectedFile();
				if(null != file)
				{
					setText(file.getAbsolutePath());
				}
				else
				{
					setText("");
				}
			}
			else
			{
				setText("");
			}

		}

		private void setText(String message)
		{
			if(null != targetTextField)
			{
				targetTextField.setText(message);
				passwordUtilityDailog.getCmdLabel().setText(getCommandLineText());
			}
		}
	}



	public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException
	{
		UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());	
		new UserPasswordCreationController();
		NotificationEvent event = new NotificationEvent(CMD_SHOW_PASSWORD_UTIL);
		NotificationRegistrar.dispatchNotification(event);	
	}


	private boolean validateString(String targetString, boolean nullable, boolean empty, String mustContain)
	{
		boolean validationStatus = false;

		//Check for nullablity
		if(true == nullable)
		{
			if(null == targetString)
			{
				return true;
			}
		}	
		else
		{
			if(null == targetString)
			{
				return false;
			}
			else
			{
				validationStatus = true;
			}
		}

		if(true == empty)
		{
			if(true == targetString.isEmpty())
			{
				return true;
			}	    
		}
		else
		{
			if(true == targetString.isEmpty())
			{
				return false;
			}
			else
			{
				validationStatus = true;
			}
		}

		if(null != mustContain)
		{
			validationStatus = targetString.contains(mustContain);
		}

		return validationStatus;
	}


	class CmdLineDisplay implements KeyListener,FocusListener
	{

		@Override
		public void keyPressed(KeyEvent e) {}
		@Override
		public void keyReleased(KeyEvent e) 
		{
			updateCommandLine();
		}
		@Override
		public void focusLost(FocusEvent e) {}


		@Override
		public void focusGained(FocusEvent e) {
			updateCommandLine();
		}
		@Override
		public void keyTyped(KeyEvent e) {
			updateCommandLine();
		}

		private void updateCommandLine() 
		{
			String cmdLine = getCommandLineText();
			passwordUtilityDailog.getCmdLabel().setText(String.format("<HTML>%s</HTML>",cmdLine));
		}



	}
	private String getCommandLineText() 
	{
		String userName = passwordUtilityDailog.getUserNameTxt().getText();
		String password = passwordUtilityDailog.getPasswordTxt().getText();
		String filePath = passwordUtilityDailog.getPwdFilePathTxt().getText();
		String utilPath = passwordUtilityDailog.getUtilityPathTxt().getText();

		String cmdString = String.format("\"%s\" -m -b \"%s\" %s %s",utilPath,filePath,userName,password);

		return cmdString;
	}

	private void resetUI()
	{
		passwordUtilityDailog.getUserNameTxt().setText("");
		passwordUtilityDailog.getPasswordTxt().setText("");
		passwordUtilityDailog.getPwdFilePathTxt().setText("");
		passwordUtilityDailog.getUtilityPathTxt().setText("");

		passwordUtilityDailog.getCmdLabel().setText("");

	}

}
